/** TestSource.cpp
*
*  Created by Penrillian, Smartphone Software Innovators 
*  See http://www.penrillian.com
*/

#include "TestHeader.h"
#include "TestDriver.h"
#include "Logger.h"

#include <xmlrpc.h>
#include <xml/parser.h>
#include "parser.h"

using namespace XmlRpc;

_LIT8(KGoodResponse, "<?xml version=\"1.0\"?>\n"
	"<methodResponse>\n"
	"   <params>\n"
	"      <param>\n"
	"         <value><string>South Dakota</string></value>\n"
	"         </param>\n"
	"      </params>\n"
	"   </methodResponse>");

_LIT(KGoodResponseString, "South Dakota");

void CParserTest::testGoodResponseL()
	{
	__UHEAP_MARK;
	CXmlRpcResult* response = new(ELeave) CXmlRpcResult();
	
	CResponseContentHandler* ch = new(ELeave) CResponseContentHandler(*response);
	Xml::CParser* parser = Xml::CParser::NewLC(_L8("text/xml"),*ch);
	parser->ParseL(KGoodResponse);
	parser->ParseEndL();
	CleanupStack::PopAndDestroy(parser);

	TS_ASSERT_EQUALS(response->ErrorCode(), KErrNone);
	
	const CValue* val = response->Result();
	TS_ASSERT_EQUALS((TInt)val->TypeId(), (TInt)XmlRpc::EString);
	
	const CString* s = static_cast<const CString*>(val);
	TS_ASSERT_EQUALS(s->Get().Compare(KGoodResponseString), 0);

	delete response;
	delete ch;
	__UHEAP_MARKEND;
	}

_LIT8(KErrorResponse, "<?xml version=\"1.0\"?>"
	"<methodResponse>"
	"   <fault>"
	"      <value>"
	"         <struct>"
	"            <member>"
	"               <name>faultCode</name>"
	"               <value><int>4</int></value>"
	"               </member>"
	"            <member>"
	"               <name>faultString</name>"
	"               <value><string>Too many parameters.</string></value>"
	"               </member>"
	"            </struct>"
	"         </value>"
	"      </fault>"
	"   </methodResponse>");
const TInt KErrorCode = 4;
_LIT(KErrorString, "Too many parameters.");

void CParserTest::testErrorResponseL()
	{
	__UHEAP_MARK;
	CXmlRpcResult* response = new(ELeave) CXmlRpcResult();
	
	CResponseContentHandler* ch = new(ELeave) CResponseContentHandler(*response);
	Xml::CParser* parser = Xml::CParser::NewLC(_L8("text/xml"),*ch);
	parser->ParseL(KErrorResponse);
	parser->ParseEndL();
	CleanupStack::PopAndDestroy(parser);

	TS_ASSERT_EQUALS(response->ErrorCode(), KErrorCode);
	
	const CValue* val = response->Result();
	TS_ASSERT_EQUALS((TInt)val->TypeId(), (TInt)XmlRpc::EString);
	
	const CString* s = static_cast<const CString*>(val);
	TS_ASSERT_EQUALS(s->Get().Compare(KErrorString), 0);

	delete response;
	delete ch;
	__UHEAP_MARKEND;
	}

_LIT8(KBadResponse, "<?xml version=\"1.0\"?>"
	"<methodResponse>"
	"   <fault>"
	"      <array>"
	"         <struct>"
	"            <member>"
	"               <name>faultCode</name>"
	"               <value><int>4</int></value>"
	"               </member>"
	"            <dodgytag>"
	"               <name>faultString</name>"
	"               <value><string>Too many parameters.</string></value>"
	"               </member>"
	"            </struct>"
	"         </value>"
	"      </fault>"
	"   </methodResponthisisn'tevenproperxmlse>");

void CParserTest::testBadResponseL()
	{
	__UHEAP_MARK;
	CXmlRpcResult* response = new(ELeave) CXmlRpcResult();
	CleanupStack::PushL(response);
	CResponseContentHandler* ch = new(ELeave) CResponseContentHandler(*response);
	CleanupStack::PushL(ch);
	Xml::CParser* parser = Xml::CParser::NewLC(_L8("text/xml"),*ch);
	TS_ASSERT_THROWS( {parser->ParseL(KBadResponse);parser->ParseEndL();}, KErrArgument);
	CleanupStack::PopAndDestroy(parser);

	CleanupStack::PopAndDestroy(ch);
	CleanupStack::PopAndDestroy(response);

	__UHEAP_MARKEND;
	}

_LIT8(KNonXmlResponse, "blah, im a text file, hahahaha");
void CParserTest::testNonXmlL()
	{
	__UHEAP_MARK;
	CXmlRpcResult* response = new(ELeave) CXmlRpcResult();
	CleanupStack::PushL(response);
	
	CResponseContentHandler* ch = new(ELeave) CResponseContentHandler(*response);
	CleanupStack::PushL(ch);
	Xml::CParser* parser = Xml::CParser::NewLC(_L8("text/plain"),*ch);
	TS_ASSERT_THROWS( {parser->ParseL(KNonXmlResponse);parser->ParseEndL();}, KErrArgument);
	CleanupStack::PopAndDestroy(parser);

	CleanupStack::PopAndDestroy(ch);
	CleanupStack::PopAndDestroy(response);

	__UHEAP_MARKEND;
	}

_LIT8(KEmptyResponse, "");
void CParserTest::testEmptyL()
	{
	__UHEAP_MARK;
	CXmlRpcResult* response = new(ELeave) CXmlRpcResult();
	CleanupStack::PushL(response);
	CResponseContentHandler* ch = new(ELeave) CResponseContentHandler(*response);
	CleanupStack::PushL(ch);
	Xml::CParser* parser = Xml::CParser::NewLC(_L8("text/plain"),*ch);
	TS_ASSERT_THROWS( {parser->ParseL(KEmptyResponse);parser->ParseEndL();}, KErrArgument);
	CleanupStack::PopAndDestroy(parser);
	CleanupStack::PopAndDestroy(ch);
	CleanupStack::PopAndDestroy(response);

	__UHEAP_MARKEND;
	}

_LIT8(KComplexResponse, "<?xml version=\"1.0\"?>\n"
	"<methodResponse>\n"
	"   <params>\n"
	"      <param>\n"
	"         <value>"
	"               <array>"
	"                   <data>"
	"<value><string>Sou&amp; &gt; &lt; Dakota</string></value>"
	"<value><struct><member><name>key1</name><value><i4>112434</i4></value></member>"
	"       <member><name>key2</name><value><double>4.23</double></value></member></struct></value>"
	"<value><base64>Zm9vYmFy</base64></value>"
    "<value><dateTime.iso8601>19840206T03:14:15</dateTime.iso8601></value>"
	"</data></array></value>"
	"         </param>\n"
	"      </params>\n"
	"   </methodResponse>");
_LIT(KComplexResponseString, "Sou& > < Dakota");
_LIT8(KComplexResponseBase64Data, "foobar");
_LIT8(KComplexResponseKey1, "key1");
_LIT8(KComplexResponseKey2, "key2");
const TInt KComplexResponseInt = 112434;
const TReal KComplexResponseDouble = 4.23;
const TInt KComplexArrayCount = 4;
void CParserTest::testComplexResponseL()
	{
	const TDateTime KComplexResponseDateTime(1984, EFebruary, 5, 3, 14, 15, 0);

	__UHEAP_MARK;
	CXmlRpcResult* response = new(ELeave) CXmlRpcResult();
	
	CResponseContentHandler* ch = new(ELeave) CResponseContentHandler(*response);
	Xml::CParser* parser = Xml::CParser::NewLC(_L8("text/xml"),*ch);
	parser->ParseL(KComplexResponse);
	parser->ParseEndL();
	CleanupStack::PopAndDestroy(parser);

	TS_ASSERT_EQUALS(response->ErrorCode(), KErrNone);
	
	const CValue* val = response->Result();
	TS_ASSERT_EQUALS((TInt)val->TypeId(), (TInt)XmlRpc::EArray);
	
	const CArray* a = static_cast<const CArray*>(val);

	TBool foundString = EFalse, foundStruct = EFalse, foundDateTime = EFalse, foundBase64 = EFalse;
	TS_ASSERT_EQUALS(a->Count(), 4);
	for (TInt i = 0; i < a->Count(); i++)
		{
		CValue* v = a->Get(i);
		switch (v->TypeId())
			{
		case XmlRpc::EString:
		    {
			const CString* s = static_cast<const CString*>(v);
			TS_ASSERT_EQUALS(s->Get().Compare(KComplexResponseString), 0);
			foundString = ETrue;
		    }
			break;
		case XmlRpc::EStruct:
		    {
			const CStruct* st = static_cast<const CStruct*>(v);
			CValue* v1 = st->GetL(KComplexResponseKey1);
			TS_ASSERT_EQUALS((TInt)v1->TypeId(), (TInt)XmlRpc::EInt);
			CInt* i = static_cast<CInt*>(v1);
			TS_ASSERT_EQUALS(i->Get(), KComplexResponseInt);
			
			CValue* v2 = st->GetL(KComplexResponseKey2);
			TS_ASSERT_EQUALS((TInt)v2->TypeId(), (TInt)XmlRpc::EDouble);
			CDouble* d = static_cast<CDouble*>(v2);
			TS_ASSERT_EQUALS(d->Get(), KComplexResponseDouble);
			foundStruct = ETrue;
		    }
			break;
		case XmlRpc::EDateTime:
       		{
			const CDateTime* dt = static_cast<const CDateTime*>(v);
			TTime t1(dt->Get());
			TTime t2(KComplexResponseDateTime);
			TS_ASSERT(t1 == t2);
			foundDateTime = ETrue;
		    }
			break;
		case XmlRpc::EBase64:
		    {
			const CBase64* b64 = static_cast<const CBase64*>(v);
			TS_ASSERT_EQUALS(b64->Get().Compare(KComplexResponseBase64Data), 0);
			foundBase64 = ETrue;
            }
			break;
		default:
			TS_FAIL("Invalid item in response");
			}
		}
	TS_ASSERT(foundBase64 && foundStruct && foundDateTime && foundString);

	delete response;
	delete ch;
	__UHEAP_MARKEND;
	}
